package top.lishuoboy.mybatisp.controller;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.AES;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import mybatis.mate.databind.RequestDataTransfer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import top.lishuoboy.dependency.base.db.MyDbUtil;
import top.lishuoboy.dependency.base.json.HuJsonUtil;
import top.lishuoboy.dependency.sb.json.JacksonUtil;
import top.lishuoboy.mybatisp.bean.User;
import top.lishuoboy.mybatisp.bean.UserSensitive;
import top.lishuoboy.mybatisp.mapper.SqlMapper;
import top.lishuoboy.mybatisp.mapper.UserMapper;
import top.lishuoboy.mybatisp.service.BaseService;
import top.lishuoboy.mybatisp.service.UserService;
import top.lishuoboy.mybatisp.vo.MyPage;

import javax.sql.DataSource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author lishuoboy
 * @date 2022/2/5 21:08
 */
@Slf4j
@RestController
public class UserController {
    /*
    @Autowired
    SqlSessionFactory sqlSessionFactory;

    @Autowired
    SqlSession sqlSession;
    */
    @Autowired
    DataSource ds;

    @Autowired
    UserMapper userMapper;

    @Autowired
    UserService userService;

    @Autowired
    BaseMapper<User> baseMapper;
    @Autowired
    BaseService<User> baseService;

    @Autowired
    SqlMapper sqlMapper;

    /**
     * http://localhost:8080/user/1    结果为 {"id":1,"userName":null,"age":18,"email":"test1@baomidou.com"}
     * http://localhost:8080/user/1    结果为 {"id":1,"userName":"Jone","age":18,"email":"test1@baomidou.com"}
     */
    @GetMapping("/user/{id}")
    private Object hello(@PathVariable int id) {
        User user = userMapper.selectByIdXml(id);
        log.info("user=={}", user);
        return user;
    }

    /**
     *
     */
    @GetMapping("/user/mp")
    private Object mp() {
        Long count = userMapper.selectCount(null);
        log.info("count=={}", count);

        User user = userMapper.selectById(1);
        log.info("user=={}", user);

        return "看后台日志";
    }

    /**
     * 重置数据库表数据
     * http://localhost:8080/reset
     */
    @GetMapping("/reset")
    private String resetDbData() {
        MyDbUtil.resetData(ds, "db_sql/lishuoboy-mybatisp.sql");
        return "重置成功";
    }

    /**
     * 插入数据
     */
    @GetMapping("/user/insert")
    private Object insert() {
        resetDbData();

        User user = new User().setUserName("张三").setAge(188).setMail("zhang@qq.com").setAddr("北京市");
        // INSERT INTO user ( user_name, age, email ) VALUES ( '张三', 188, 'zhang@qq.com' )
        int insertCount = userMapper.insert(user); // 关注主键自增策略@TableId(type = IdType.***)

        log.info("自增的ID, user.getId()=={}", user.getId());
        log.info("插入记录条数, insertCount=={}", insertCount);
        return insertCount;
    }

    /** service_save */
    @GetMapping("/user/service_save")
    private String serviceSave() {
        resetDbData();

        boolean saveSuccess;
        // INSERT INTO user ( id, user_name ) VALUES ( 1, '张三1' )
//        saveSuccess = userService.save(new User().setUserName("张三1").setId(1));   // 主键冲突

        // SELECT id,user_name,age,email AS mail FROM user WHERE id=2
        // UPDATE user SET user_name='张三2' WHERE id=2
        saveSuccess = userService.saveOrUpdate(new User().setUserName("张三2").setId(2));  // 没有插入，有则更新byId

        // INSERT INTO user ( user_name ) VALUES ( '张三3' )
        User user = new User().setUserName("张三3");
        saveSuccess = userService.save(user);
        log.info("自增的ID, user.getId()=={}", user.getId());

        // INSERT INTO user ( user_name ) VALUES ( '张三4' )
        saveSuccess = userService.saveOrUpdate(new User().setUserName("张三4"));

        return "看后台日志";
    }

    /** service_save_batch，并非真正的mysql批量。真正的批量插入见serviceSaveBatch2()，需url增加?rewriteBatchedStatements=true。批量插入性能测试见serviceSaveBatch3() */
    @GetMapping("/user/service_save_batch")
    private String serviceSaveBatch() {
        resetDbData();

        boolean saveSuccess;
        List<User> userList = ListUtil.list(false,
            new User().setUserName("张三1").setId(1),
            new User().setUserName("张三6").setId(6),
            new User().setUserName("张三7")
        );
        // INSERT INTO user ( id, user_name ) VALUES ( 1, '张三1' )
        // INSERT INTO user ( id, user_name ) VALUES ( 6, '张三6' )
        // INSERT INTO user ( user_name ) VALUES ( '张三7' )
        saveSuccess = userService.saveBatch(userList, 1000);   // 主键冲突，一个失败全回滚。batchSize – 每次的数量，不写就是默认1000

        // SELECT id,user_name,age,email AS mail,version FROM user WHERE id=1
        // UPDATE user SET user_name='张三1' WHERE id=1
        // SELECT id,user_name,age,email AS mail,version FROM user WHERE id=6
        // INSERT INTO user ( id, user_name ) VALUES ( 6, '张三6' )
        // INSERT INTO user ( user_name ) VALUES ( '张三7' )
        saveSuccess = userService.saveOrUpdateBatch(userList, 1000);  // 没有插入，有则更新byId 。batchSize – 每次的数量，不写就是默认1000
        log.info("自增的ID回填bean, userList.get(1).getId()=={}", userList.get(1).getId());

        return "看后台日志";
    }

    /**
     * service_save_batch2
     * 真正的mysql批量插入。需url增加?rewriteBatchedStatements=true。批量插入性能测试见serviceSaveBatch3()
     * 测试时关闭sql日志，输出日志很耗资源
     */
    @GetMapping("/user/service_save_batch2")
    private String serviceSaveBatch2() {
        // 动态修改日志级别
        LoggerContext loggerContext = ((LoggerContext) LoggerFactory.getILoggerFactory());
        loggerContext.getLogger("top.lishuoboy.mybatisp.mapper").setLevel(Level.INFO);

        boolean saveSuccess;
        // 测试时关闭sql日志，输出日志很耗资源
        // 注意：不要共用userList，因为 MP insert会自动回填 id
        List<User> userList = new ArrayList<>();
        List<User> userList2 = new ArrayList<>();

        for (int i = 6; i <= 10; i++) {
            if (i <= 7) {
                userList.add(new User().setUserName("张三" + i).setId(i));
                userList2.add(new User().setUserName("张三" + i).setId(i));
            } else {
                userList.add(new User().setUserName("张三" + i));
                userList2.add(new User().setUserName("张三" + i));
            }
        }
        // 注意：IDEA 的 MyBatis Log插件看不出批量插入sql效果
        // INSERT INTO USER ( id, user_name ) VALUES ( 6, '张三6' ),( 7, '张三7' )
        // INSERT INTO user  ( user_name )  VALUES  ( '张三8' ),( '张三9' ),( '张三10' ),( '张三11' ),( '张三12' ),………………
        resetDbData();  // 重置数据
        saveSuccess = userService.saveBatch(userList, 10000);   // 主键冲突，一个失败全回滚。batchSize – 每次的数量，不写就是默认1000
        // 注意：张三6 和 张三7 自动回填的值不对，回填的 7 和 8，应该是6、7
        log.info("userList.get(0).getId()=={}", userList.get(0).getId());   // 自增的ID回填bean, userList.get(0).getId()==7

        // 注意：IDEA 的 MyBatis Log插件看不出批量插入sql效果
        // SELECT id,user_name,age,email AS mail,version FROM user WHERE id=6
        // INSERT INTO user ( id, user_name ) VALUES ( 6, '张三6' )
        // SELECT id,user_name,age,email AS mail,version FROM user WHERE id=7
        // INSERT INTO user ( id, user_name ) VALUES ( 7, '张三7' )
        // INSERT INTO user  ( user_name )  VALUES  (8,'张三8'),( '张三9' ),( '张三10' ),( '张三11' ),( '张三12' ),………………
        resetDbData();  // 重置数据
        saveSuccess = userService.saveOrUpdateBatch(userList2, 10000);  // 没有插入，有则更新byId 。batchSize – 每次的数量，不写就是默认1000
        log.info("userList2.get(0).getId()=={}", userList2.get(0).getId()); // 自增的ID回填bean, userList2.get(0).getId()==6

        return "看后台日志";
    }

    /**
     * mysql批量插入的性能测试。
     * 相关参考 serviceSaveBatch()、serviceSaveBatch2()
     */
    @GetMapping("/user/service_save_batch3")
    private String serviceSaveBatch3() {
        // 动态修改日志级别
        LoggerContext loggerContext = ((LoggerContext) LoggerFactory.getILoggerFactory());
        loggerContext.getLogger("top.lishuoboy.mybatisp.mapper").setLevel(Level.INFO);

        TimeInterval timeInterval = new TimeInterval();

        // 测试时关闭sql日志，输出日志很耗资源
        // 注意：不要共用userList，因为 MP insert会自动回填 id
        List<User> userList1 = new ArrayList<>();  // 用户set了主键id的值，使用 saveOrUpdateBatch() 插入性能低,因为每条都要判断数据库是否存在。
        List<User> userList2 = new ArrayList<>();  // 用户set了主键id的值，使用 saveBatch() 防止每条都要判断数据库是否存在，提高性能。但是可能主键冲突报错。
        List<User> userList3 = new ArrayList<>();  // 用户不set主键id的值。且需要注解 @TableId(type = IdType.AUTO)，使用 saveOrUpdateBatch()、防止每条都要判断数据库是否存在，提高性能。

        int count = 100000;
        for (int i = 6; i <= count; i++) {
            userList1.add(new User().setUserName("张三" + i).setId(i));
            userList2.add(new User().setUserName("张三" + i).setId(i));
            userList3.add(new User().setUserName("张三" + i));
        }

        resetDbData();  // 重置数据
        timeInterval.start();
//        userService.saveOrUpdateBatch(userList1, 10000);
        log.warn("批量插入数据量count=={}, 用时 {} ms", count, timeInterval.intervalMs());   // 批量插入数据量count==100000, 用时 97840 ms

        resetDbData();
        timeInterval.restart();
        userService.saveBatch(userList2, 10000);  // 直接插入，可能主键冲突报错
        log.warn("批量插入数据量count=={}, 用时 {} ms", count, timeInterval.intervalMs());   // 批量插入数据量count==100000, 用时 4485 ms

        resetDbData();
        timeInterval.restart();
        userService.saveOrUpdateBatch(userList3, 10000);
        log.warn("批量插入数据量count=={}, 用时 {} ms", count, timeInterval.intervalMs());   // 批量插入数据量count==100000, 用时 4452 ms

        return "看后台日志";
    }

    /**
     * 更新数据
     */
    @GetMapping("/user/update")
    private Object update() {
        resetDbData();

        User user;

        // UPDATE user SET user_name='张三', age=188 WHERE id=1
        user = new User().setId(1).setUserName("张三").setAge(188);
        int count = userMapper.updateById(user);

        // UPDATE user SET user_name='李四', age=188 WHERE id=null
        user = new User().setUserName("张三").setAge(288);
        count = userMapper.updateById(user);

        // UPDATE user SET user_name='李四', age=388 WHERE (id = 3)
        user = new User().setUserName("李四").setAge(388);
        QueryWrapper queryWrapper = new QueryWrapper<User>().eq("id", 3);
        count = userMapper.update(user, queryWrapper);  // queryWrapper 为 null 时，无where、更新全表

        // UPDATE user SET user_name='王五1', age=4881, user_name='王五2',age=4882 WHERE (id = 4)
        user = new User().setUserName("王五1").setAge(4881);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("user_name", "王五2").set("age", 4882).eq("id", 4);  // 注意是数据库字段名字
        count = userMapper.update(user, updateWrapper); // 两个参数不能都为null。updateWrapper 为 null 时，无where、更新全表

        return "update完成";
    }

    /**
     * service_update 更新数据
     */
    @GetMapping("/user/service_update")
    private Object serviceUpdate() {
        resetDbData();

        User user;
        boolean isSuccess;


        // UPDATE user SET user_name='张三', age=188 WHERE id=1
        user = new User().setId(1).setUserName("张三").setAge(188);
        isSuccess = userService.updateById(user);

        // UPDATE user SET user_name='李四', age=188 WHERE id=null
        user = new User().setUserName("张三").setAge(288);
        isSuccess = userService.updateById(user);

        // UPDATE user SET user_name='李四', age=388 WHERE (id = 3)
        user = new User().setUserName("李四").setAge(388);
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>().eq("id", 3);
        isSuccess = userService.update(user, queryWrapper);  // queryWrapper 为 null 时，无where、更新全表

        // UPDATE user SET user_name='王五1', age=4881, user_name='王五2',age=4882 WHERE (id = 4)
        user = new User().setUserName("王五1").setAge(4881);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("user_name", "王五2").set("age", 4882).eq("id", 4);  // 注意是数据库字段名字
        isSuccess = userService.update(user, updateWrapper); // 两个参数不能都为null。updateWrapper 为 null 时，无where、更新全表

        return "update完成";
    }

    /**
     * service_update_BatchById 批量更新数据
     */
    @GetMapping("/user/service_update_BatchById")
    private Object serviceUpdateBatchById() {
        resetDbData();

        boolean isSuccess;

        List<User> userList = ListUtil.list(false,
            new User().setUserName("张三").setId(1),
            new User().setUserName("张三").setId(2),
            new User().setUserName("李四").setId(3),
            new User().setUserName("王五")
        );

        // SET autocommit=0
        // SELECT @@session.transaction_read_only
        // SELECT @@session.transaction_read_only
        // UPDATE user  SET user_name='张三'  WHERE id=1;
        // UPDATE user  SET user_name='张三'  WHERE id=2;
        // UPDATE user  SET user_name='李四'  WHERE id=3;
        // UPDATE user  SET user_name='王五'  WHERE id=null
        // commit
        // SET autocommit=1
        isSuccess = userService.updateBatchById(userList, 1000);   // batchSize – 更新批次数量, 默认是1000

        return "update完成";
    }


    /**
     * 删除数据
     */
    @GetMapping("/user/delete")
    private Object delete() {
        resetDbData();

        // DELETE FROM user WHERE id=1
        int count = userMapper.deleteById(1);

        // DELETE FROM user WHERE id=2
        User user;
        user = new User().setId(2);
        count = userMapper.deleteById(user);

        // DELETE FROM user WHERE id IN ( 3 , 4 )
        count = userMapper.deleteBatchIds(Arrays.asList(3, 4));

        // DELETE FROM user WHERE (id = 5)
        QueryWrapper queryWrapper = new QueryWrapper<User>().eq("id", 5);
        count = userMapper.delete(queryWrapper); // queryWrapper 为 null 时，无where、删除全表

        // DELETE FROM user WHERE user_name = '张三' AND age = 18
        Map<String, Object> map = MapUtil.<String, Object>builder("user_name", "张三").put("age", 18).build();
        count = userMapper.deleteByMap(map);

        return "delete 完成";
    }

    /**
     * service_remove 删除数据
     */
    @GetMapping("/user/service_remove")
    private Object serviceRemove() {
        resetDbData();

        boolean isSuccess;
        // DELETE FROM user WHERE id=1
        isSuccess = userService.removeById(1);

        // DELETE FROM user WHERE id=2
        User user;
        user = new User().setId(2);
        isSuccess = userService.removeById(user);

        // 居然不是  IN ( 3 , 4 )，还是用 userMapper.deleteBatchIds() 吧
        // SET autocommit=0
        // DELETE FROM user WHERE id=3
        // DELETE FROM user WHERE id=4
        // commit
        // SET autocommit=1
        isSuccess = userService.removeBatchByIds(Arrays.asList(3, 4), 1000);

        // DELETE FROM user WHERE user_name = '张三' AND age = 18
        Map map = MapUtil.<String, Object>builder("user_name", "张三").put("age", 18).build();
        isSuccess = userService.removeByMap(map);

        return "remove 完成";
    }

    /**
     * 查询数据
     * // 根据 ID 查询
     * T selectById(Serializable id);
     * // 根据 entity 条件，查询一条记录
     * T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
     *
     * // 查询（根据ID 批量查询）
     * List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
     * // 根据 entity 条件，查询全部记录
     * List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
     * // 查询（根据 columnMap 条件）
     * List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
     * // 根据 Wrapper 条件，查询全部记录
     * List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
     * // 根据 Wrapper 条件，查询全部记录。注意： 只返回第一个字段的值
     * List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
     *
     * // 根据 entity 条件，查询全部记录（并翻页）
     * IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
     * // 根据 Wrapper 条件，查询全部记录（并翻页）
     * IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
     * // 根据 Wrapper 条件，查询总记录数
     * Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
     */
    @GetMapping("/user/select")
    private Object select() {
        resetDbData();

        QueryWrapper queryWrapper;
        User user;
        List<User> userList;

        /** 一、以下查询单条返回 User */
        // SELECT id,user_name,age,email AS mail FROM user WHERE id=1
        user = userMapper.selectById(1);
        log.warn("user=={}", user);

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id = 2)
        queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", 2);
        user = userMapper.selectOne(queryWrapper);   // QueryWrapper为null时，sql无where，所以查到多条记录，抛异常 One record is expected, but the query result is multiple records
        log.warn("user=={}", user);

        /** 二、以下查询多条返回 List<User> */
        // SELECT id,user_name,age,email AS mail FROM user WHERE id IN ( 1 , 2 , '3' )
        userList = userMapper.selectBatchIds(Arrays.asList(1, 2, "3"));
        log.warn("userList=={}", userList);

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id > 3)
        queryWrapper = new QueryWrapper();
        queryWrapper.gt("id", 3);
        userList = userMapper.selectList(queryWrapper);  // QueryWrapper为null时，sql无where，返回全表记录
        log.warn("userList=={}", userList);

        // SELECT id,user_name,age,email AS mail FROM user WHERE id = '1'
        Map<String, Object> map = MapUtil.<String, Object>builder("id", "1").build();
        userList = userMapper.selectByMap(map);
        log.warn("userList=={}", userList);

        /** 三、以下查询多条返回  List<Object> 或 List<Map<String, Object>> */
        // SELECT id,user_name,age,email AS mail FROM user
        List<Map<String, Object>> mapList = userMapper.selectMaps(null);  // QueryWrapper为null时，sql无where，返回所有记录
        log.warn("mapList=={}", mapList);

        // SELECT id,user_name,age,email AS mail FROM user
        List<Object> objectList = userMapper.selectObjs(null);  // 注意： 只返回第一个字段的值。 QueryWrapper为null时，sql无where，返回所有记录
        log.warn("objectList=={}", objectList);   // objectList==[1, 2, 3, 4, 5]

        /** 四、以下查询多条返回  IPage<User> 或 IPage<Map<String, Object>> */
        queryWrapper = new QueryWrapper();
        queryWrapper.lt("id", 5);
        // SELECT COUNT(*) AS total FROM user WHERE (id < 5)
        // SELECT id,user_name,age,email AS mail FROM user WHERE (id < 5) LIMIT 2,2
        Page<User> page = new Page<>(2, 2);
        IPage<User> userIPage = userMapper.selectPage(page, queryWrapper);  // QueryWrapper为null时，sql无where，返回limit记录
        List<User> userRecordList = userIPage.getRecords();
        // 总数==4, 页数==2, userRecords==[User(id=3, userName=Tom, age=28, mail=test3@baomidou.com, addr=null), User(id=4, userName=Sandy, age=21, mail=test4@baomidou.com, addr=null)]
        log.warn("总数=={}, 页数=={}, userRecords=={}", userIPage.getTotal(), userIPage.getPages(), userRecordList);

        // SELECT COUNT(*) AS total FROM user WHERE (id < 5)
        // SELECT id,user_name,age,email AS mail FROM user WHERE (id < 5) LIMIT 2
        Page page2 = new Page<>(1, 2);
        IPage<Map<String, Object>> mapIPage = userMapper.selectMapsPage(page2, queryWrapper);  // QueryWrapper为null时，sql无where，返回limit记录
        List<Map<String, Object>> mapRecordList = mapIPage.getRecords();
        // 总数==4, 页数==2, mapRecordList==[{mail=test1@baomidou.com, user_name=Jone, id=1, age=18}, {mail=test2@baomidou.com, user_name=Jack, id=2, age=20}]
        log.warn("总数=={}, 页数=={}, mapRecordList=={}", userIPage.getTotal(), userIPage.getPages(), mapRecordList);

        return "select 完成";
    }

    /**
     * 查询count
     * // 根据 Wrapper 条件，查询总记录数
     * Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
     */
    @GetMapping("/user/selectCount")
    private Object selectCount() {
        resetDbData();

        //  SELECT COUNT( * ) FROM user WHERE (id < 10)
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.lt("id", 10);  // id 小于 10
        Long count = userMapper.selectCount(queryWrapper);  // QueryWrapper为null时，sql无where，返回所有记录条数
        log.warn("count=={}", count);  // 5

        return "selectCount==" + count;
    }

    /**
     * where条件构造器 Wrapper
     */
    @GetMapping("/user/wrapper")
    private Object wrapper() {
        resetDbData();

        // 一、AbstractWrapper
        QueryWrapper<User> queryWrapper;
        List<User> userList;

        // 1、 全等于allEq
        // SELECT id,user_name,age,email AS mail FROM user WHERE (id = 1 AND user_name = 'Jone' AND age IS NULL)
        Map<String, Object> eqMap = HuJsonUtil.toMap("{id:1,user_name:'Jone',age:null}");
        queryWrapper = new QueryWrapper();
        queryWrapper.allEq(eqMap);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id = 1 AND user_name = 'Jone')
        queryWrapper = new QueryWrapper();
        queryWrapper.allEq(eqMap, false);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 2、等于eq、不等于ne、大于gt、小于lt、大于等于ge，小于等于le
        // SELECT id,user_name,age,email AS mail FROM user WHERE (id = 1)
        queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", 1);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id <> 1)
        queryWrapper = new QueryWrapper();
        queryWrapper.ne("id", 1);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id >= 1)
        queryWrapper = new QueryWrapper();
        queryWrapper.ge("id", 1);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 3、between,notBetween
        // SELECT id,user_name,age,email AS mail FROM user WHERE (id BETWEEN 2 AND 4)
        queryWrapper = new QueryWrapper();
        queryWrapper.between("id", 2, 4);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 4、like、notLike、likeLeft、likeRight
        // SELECT id,user_name,age,email AS mail FROM user WHERE (user_name LIKE %a%)
        queryWrapper = new QueryWrapper();
        queryWrapper.like("user_name", "a");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // SELECT id,user_name,age,email AS mail FROM user WHERE (user_name LIKE J%)
        queryWrapper = new QueryWrapper();
        queryWrapper.likeRight("user_name", "J");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 5、isNull、isNotNull
        // SELECT id,user_name,age,email AS mail FROM user WHERE (user_name IS NOT NULL)
        queryWrapper = new QueryWrapper();
        queryWrapper.isNotNull("user_name");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 6、in、notIn、inSql、notInSql
        // SELECT id,user_name,age,email AS mail FROM user WHERE (id IN (1,2,3))
        queryWrapper = new QueryWrapper();
        queryWrapper.in("id", 1, 2, 3);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id IN (select id from user))
        queryWrapper = new QueryWrapper();
        queryWrapper.inSql("id", "select id from user");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 7、orderByAsc、orderByDesc、orderBy、isUseAnnotationOrderBy
        // SELECT id,user_name,age,email AS mail FROM user ORDER BY id ASC,age ASC
        queryWrapper = new QueryWrapper();
        queryWrapper.orderByAsc("id", "age");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 8、groupBy
        // SELECT id,user_name,age,email AS mail FROM user GROUP BY id,age
        queryWrapper = new QueryWrapper();
        queryWrapper.groupBy("id", "age");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 9、having
        // SELECT id,user_name,age,email AS mail FROM user GROUP BY id HAVING id > 3 and max(age) > 10 AND id > 1 and max(age) > 11
        queryWrapper = new QueryWrapper();
        queryWrapper.groupBy("id");
        queryWrapper.having("id > 2 and max(age) > 10");
        queryWrapper.having("id > {0} and max(age) > {1}", 1, 11);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);


        // 10、or、and 【太复杂，不如直接用apply】注意事项: 主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)
        // SELECT id,user_name,age,email AS mail FROM user WHERE (id <= 2 OR id >= 4 AND age >= 20)
        queryWrapper = new QueryWrapper();
        queryWrapper.le("id", 2);
        queryWrapper.or();
        queryWrapper.ge("id", 4);
        queryWrapper.ge("age", 20);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // QueryWrapper 指定了泛型可以链式写
        // SELECT id,user_name,age,email AS mail FROM user WHERE (id <= 2 OR id >= 4 AND age >= 20)
        queryWrapper = new QueryWrapper();
        queryWrapper.le("id", 2).or().ge("id", 4).ge("age", 20);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // and嵌套、or嵌套。注意与上面的区别
        // SELECT id,user_name,age,email AS mail FROM user WHERE ((id <= 2 OR id >= 4) AND (age >= '20'))
        queryWrapper = new QueryWrapper();
        queryWrapper
            .and(i -> i.le("id", 2).or().ge("id", 4))
            .and(i -> i.ge("age", "20"));
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 11、apply
        // SELECT id,user_name,age,email AS mail FROM user WHERE ((id <= 2 OR id >= 4) AND age >= 20)
        queryWrapper = new QueryWrapper();
        queryWrapper.apply("(id <= {0} OR id >= {1}) AND age >= {2}", 2, 4, 20);
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 12、last 比如 limit
        // SELECT id,user_name,age,email AS mail FROM user limit 2
        queryWrapper = new QueryWrapper();
        queryWrapper.last("limit 2");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 13、exists、notExists
        // SELECT id,user_name,age,email AS mail FROM user WHERE (EXISTS (SELECT 1 FROM user where id=1))
        queryWrapper = new QueryWrapper();
        queryWrapper.exists("SELECT 1 FROM user where id=1");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 二、QueryWrapper
        // 14、select
        // SELECT id,user_name FROM user
        queryWrapper = new QueryWrapper();
        queryWrapper.select("id", "user_name");
        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        // 三、UpdateWrapper
        UpdateWrapper<User> updateWrapper;

        // 15 set、setSql
        // UPDATE user SET age=1111, user_name='张三' WHERE (id < 3)
        updateWrapper = new UpdateWrapper();
        updateWrapper.set("user_name", "张三").lt("id", 3);
        int count = userMapper.update(new User().setAge(1111), updateWrapper);
        log.warn("count=={}", count);

        // UPDATE user SET age=2222, user_name='李四' WHERE (id > 3)
        updateWrapper = new UpdateWrapper();
        updateWrapper.setSql("user_name='李四'").gt("id", 3);
        count = userMapper.update(new User().setAge(2222), updateWrapper);
        log.warn("count=={}", count);

        // 四、综合测试
        /*
        SELECT id, user_name
        FROM USER
        WHERE(
        		age >= 10
        		AND id BETWEEN 1 AND 5
        		AND email LIKE '%test%'
        		AND email LIKE 'test%'
        		AND id IS NOT NULL
        		AND id IN ( 1, 2, 3, 4, 5 )
        		AND id IN ( SELECT id FROM USER )
        	AND EXISTS ( SELECT id FROM USER WHERE id = 1 )
        )
        GROUP BY
        	id
        HAVING
        	avg( age ) > 10
        ORDER BY id DESC
        LIMIT 10
        */
        queryWrapper = new QueryWrapper();
        queryWrapper
            .select("id", "user_name")

//            .allEq(eqMap,false)
            .ge("age", 10)
            .between("id", 1, 5)
            .like("email", "test")
            .likeRight("email", "test")
            .isNotNull("id")
            .in("id", 1, 2, 3, 4, 5)
            .inSql("id", "select id from user")
            .groupBy("id")
            .having("avg(age) > {0}", 10)
            .exists("select id from user where id={0}", 1)
            .last("limit 10")
            .orderByDesc("id");

        userList = userMapper.selectList(queryWrapper);
        log.warn("userList=={}", userList);

        return "看后台日志";
    }

    /** ActiveRecord modelInsert */
    @GetMapping("/user/model_insert")
    private String modelInsert() {
        resetDbData();

        // 一、 insert
        // INSERT INTO user ( id, user_name ) VALUES ( 1, '张三1' )
//        new User().setUserName("张三1").setId(1).insert();   // 主键冲突
        // SELECT id,user_name,age,email AS mail FROM user WHERE id=2
        // UPDATE user SET user_name='张三2' WHERE id=2
        new User().setUserName("张三2").setId(2).insertOrUpdate();  // 没有插入，有则更新byId
        // INSERT INTO user ( user_name ) VALUES ( '张三3' )
        new User().setUserName("张三3").insert();
        // INSERT INTO user ( user_name ) VALUES ( '张三4' )
        new User().setUserName("张三4").insertOrUpdate();

        return "看后台日志";
    }

    /** ActiveRecord modelUpdate */
    @GetMapping("/user/model_update")
    private String modelUpdate() {
        resetDbData();

        // 二、update
        // 无 sql
//        new User().setUserName("张三1").updateById();  // 没有id,报错
        // UPDATE user SET user_name='张三2' WHERE id=2
        boolean isSuccess = new User().setId(2).setUserName("张三2").updateById();

        // User.setId()不起作用，updateWrapper.set("id", "4")起作用
        // UPDATE user SET user_name='张三3', age='100' WHERE (email = 'test3@baomidou.com')
        UpdateWrapper<User> updateWrapper = new UpdateWrapper();
        updateWrapper.set("age", "100").eq("email", "test3@baomidou.com");
        isSuccess = new User().setId(3).setUserName("张三3").update(updateWrapper); // updateWrapper 为 null 时，无where、更新全表

        // User.setId()不起作用，updateWrapper.set("id", "4")起作用
        // UPDATE user SET user_name='张三4', age='4',id='4' WHERE (email = 'test4@baomidou.com')
        updateWrapper = new UpdateWrapper();
        updateWrapper.set("age", "4").eq("email", "test4@baomidou.com").set("id", "4");
        isSuccess = new User().setId(4).setUserName("张三4").update(updateWrapper); // updateWrapper 为 null 时，无where、更新全表

        return "看后台日志";
    }

    /** ActiveRecord modelDelete */
    @GetMapping("/user/model_delete")
    private String modelDelete() {
        resetDbData();

        // 三、 delete
        // DELETE FROM user WHERE id=1
        new User().setId(1).setUserName("张三").deleteById();
        // DELETE FROM user WHERE id=2
        new User().setId(1).setUserName("张三").deleteById(2);

        // DELETE FROM user WHERE (id = '3' AND email = 'test3@baomidou.com')
        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", "3").eq("email", "test3@baomidou.com");
        new User().setId(1).setUserName("张三").delete(queryWrapper); // queryWrapper 为 null 时，无where、删除全表

        return "看后台日志";
    }

    /** ActiveRecord modelSelect */
    @GetMapping("/user/model_select")
    private String modelSelect() {
        resetDbData();

        User user;
        List<User> userList;

        // 四、 select
        // SELECT id,user_name,age,email AS mail FROM user WHERE id=1
        user = new User().setId(1).selectById();

        // SELECT id,user_name,age,email AS mail FROM user WHERE id=2
        user = new User().setId(1).selectById(2);

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id = '3' AND email = 'test3@baomidou.com')
        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", "3").eq("email", "test3@baomidou.com");
        user = new User().setId(1).selectOne(queryWrapper); // QueryWrapper为null时，sql无where，返回第一条记录

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id >= '3')
        queryWrapper = new QueryWrapper();
        queryWrapper.ge("id", "3");
        userList = new User().setId(1).selectList(queryWrapper); // QueryWrapper为null时，sql无where，返回全表记录

        // SELECT id,user_name,age,email AS mail FROM user
        userList = new User().setId(1).selectAll();

        // SELECT id,user_name,age,email AS mail FROM user WHERE (id >= '3') LIMIT 2,2
        Page<User> page = new Page<>(2, 2);
        Page<User> userPage = new User().setId(1).selectPage(page, queryWrapper); // QueryWrapper为null时，sql无where，返回limit记录
        userList = userPage.getRecords();
        // 总数==3, 页数==2, userList==[User(id=5, userName=Billie, age=24, mail=test5@baomidou.com, addr=null)]
        log.warn("总数=={}, 页数=={}, userList=={}", userPage.getTotal(), userPage.getPages(), userList);

        // SELECT COUNT( * ) FROM user WHERE (id >= '3')
        long selectCount = new User().setId(1).selectCount(queryWrapper);

        return "看后台日志";
    }

    /**
     * 乐观锁 @Version
     * 【使用方式】
     * 1、ioc注入乐观锁拦截器 OptimisticLockerInnerInterceptor
     * 2、数据库 增加字段“version”，并设置默认值为1
     * 3、bean  增加字段“version”，并注解 @Version
     * 4、更新前先查出来带version的bean，更新时会带上version并自动+1 或 更新时间戳
     *
     * 注意：
     * ● 支持的数据类型(java类型)只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
     * ● 整数类型下 newVersion = oldVersion + 1
     * ● newVersion 会回写到 entity 中
     * ● 仅支持 updateById(id) 与 update(entity, wrapper) 方法
     * ● 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
     */
    @GetMapping("/user/version")
    private String version() {
        resetDbData();

        // 4、更新前先查出来带version的bean，更新时会带上version并自动+1 或 更新时间戳
        // 先查，假装是从数据库查出来的
//        User user = userMapper.selectById(1);
        User user = new User().setVersion(1).setId(1);

        // 4、更新前先查出来带version的bean，更新时会带上version并自动+1 或 更新时间戳
        // UPDATE user SET user_name='张三', version=2 WHERE id=1 AND version=1
        user.setUserName("张三");
        int count = userMapper.updateById(user);

        if (count > 0) {
            log.info("更新成功count=={}", count);
        } else {
            log.warn("更新失败count=={}", count);
        }

        // newVersion 会回写到 entity 中
        log.info("user.getVersion()=={}", user.getVersion());  // user.getVersion()==2

        return "看后台日志";
    }

    /**
     * 逻辑删除 @TableLogic
     * 只对自动注入的 sql 起效:
     * 插入: 不作限制
     * 删除: 转变为 更新
     * 更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
     * 查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
     *
     * 【使用方式】
     * 1、数据库 增加字段“deleted”，并设置默认值为0
     * 2、bean  增加字段“deleted”，并注解 @TableLogic。配置文件已配置全局逻辑删除的实体字段名（logic-delete-field: deleted），且字段名字一致的，可以不在bean上注解 @TableLogic(since 3.3.0
     *
     * 支持所有java数据类型(推荐使用 Integer,Boolean,LocalDateTime)
     * 如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now()
     *
     * 注意：
     * 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案，但实际就是删除。
     * 如果你需要频繁查出来看就不应使用逻辑删除，而是以一个状态去表示。
     */
    @GetMapping("/user/logic_delete")
    private String logicDelete() {
        resetDbData();

        // 逻辑删除
        //插入: 不作限制
        //删除: 转变为 更新
        //更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段
        //查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段

        // INSERT INTO user ( user_name ) VALUES ( '张三6' )
        long count = userMapper.insert(new User().setUserName("张三6"));

        // UPDATE user SET deleted=1 WHERE id=1 AND deleted=0
        count = userMapper.deleteById(1);

        // UPDATE user SET user_name='张三' WHERE id=2 AND deleted=0
        count = userMapper.updateById(new User().setId(2).setUserName("张三"));

        // SELECT id,user_name FROM user WHERE deleted=0
        List<User> userList = userMapper.selectList(new QueryWrapper<User>().select("id", "user_name"));

        // SELECT COUNT( * ) FROM user WHERE deleted=0
        count = userMapper.selectCount(null);

        return "看后台日志";
    }

    /**
     * 数据安全保护
     * 【使用方式】
     * 1、生成密钥randomKey然后对data加密
     * 2、将加密后的data写到配置文件中，前缀为mpw：
     * 3、启动添加程序参数--mpw.key=${randomKey},本例中为--mpw.key=5387026759173bb0 。加密配置 mpw: 开头紧接加密内容（ 非数据库配置专用 YML 中其它配置也是可以使用的 ）
     */
    @Test
    public void mpw() {
        // 生成 16 位随机 AES 密钥
        String randomKey = AES.generateRandomKey();

        // 随机密钥加密
        String username = AES.encrypt("root", randomKey);
        String password = AES.encrypt("1234", randomKey);
        // randomKey==5387026759173bb0, username==yXIJHs1b6Tk6GyqXEsJMqg==, password==u/EbuEFkiC6FYP/PeaM/4A==
        log.info("randomKey=={}, username=={}, password=={}", randomKey, username, password);
    }

    /**
     * 万能mp BaseMapper 和 BaseService，更简洁
     */
    @GetMapping("/baseMapper")
    private Object baseMapper() {
        resetDbData();

        List<User> userList = ListUtil.list(true,
            baseMapper.selectById(1),
            baseService.getById(2));
        log.info("userList=={}", userList);

        return userList;
    }

    /**
     * 万能 sql 执行器
     * 单表优先用BaseMapper<T>、BaseService<T>; 多表、DDL需写sql用 SqlMapper
     * 与mybatis中的不同是 select返回的是Long，不是Integer
     */
    @GetMapping("/sqlMapper")
    public void sqlMapper() {
        resetDbData();

        BigInteger id;
        String name, email;


        List<User> userList = sqlMapper.selectList("select * from user", User.class);
        log.warn("userList=={}", userList);             // userList==[User(id=1, userName=Jone, age=18, mail=null, addr=null, version=1, deleted=false), User(id=2, userName=Jack, age=20, mail=null, addr=null, version=1, deleted=false), User(id=3, userName=Tom, age=28, mail=null, addr=null, version=1, deleted=false), User(id=4, userName=Sandy, age=21, mail=null, addr=null, version=1, deleted=false), User(id=5, userName=Billie, age=24, mail=null, addr=null, version=1, deleted=false)]

        List<Map<String, Object>> mapList1 = sqlMapper.selectList("select id,user_name from user");
        Map<String, Object> map = mapList1.get(0);
        id = (BigInteger) map.get("id");
        name = (String) map.get("user_name");
        log.warn("{}, {}", map.getClass(), map);        // class java.util.HashMap, {user_name=Jone, id=1}
        log.warn("{}, {}", id.getClass(), id);          // class java.lang.Long, 1
        log.warn("{}, {}", name.getClass(), name);      // class java.lang.String, Jone

        List<Map<String, String>> mapList2 = sqlMapper.selectList("select user_name, email from user");
        Map<String, String> map2 = mapList2.get(0);
        name = map2.get("user_name");
        email = map2.get("email");
        log.warn("{}, {}", map2.getClass(), map2);      // class java.util.HashMap, {user_name=Jone, email=test1@baomidou.com}
        log.warn("{}, {}", name.getClass(), name);      // class java.lang.String, Jone
        log.warn("{}, {}", email.getClass(), email);    // class java.lang.String, test1@baomidou.com

        MyPage myPage = new MyPage(2, 2, "id desc,age asc,user_name").setSearchCount(true);
        List<Map<String, Object>> mapList3 = sqlMapper.selectList("select * from user", myPage);
        log.warn("mapList3=={}", mapList3);             // mapList3==Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=5, pages=3, reasonable=false, pageSizeZero=false}[{tenant_id=1, deleted=0, user_name=Tom, id=3, version=1, age=28, email=test3@baomidou.com}, {tenant_id=1, deleted=0, user_name=Jack, id=2, version=1, age=20, email=test2@baomidou.com}]
        List<User> userList3 = sqlMapper.selectList("select * from user", myPage, User.class);
        log.warn("userList3=={}", userList3);           // userList3==[User(id=3, userName=Tom, age=28, mail=null, addr=null, version=1, deleted=false, createTime=null, updateTime=null, tenantId=1), User(id=2, userName=Jack, age=20, mail=null, addr=null, version=1, deleted=false, createTime=null, updateTime=null, tenantId=1)]

        Page<Map<String, Object>> mapPage = sqlMapper.selectPage("select * from user", myPage);
        log.warn("mapPage=={}", JacksonUtil.toStr(mapPage));
        Page<User> userPage = sqlMapper.selectPage("select * from user", myPage, User.class);
        log.warn("userPage=={}", JacksonUtil.toStr(userPage));

        myPage = new MyPage().setOrders("id desc,user_name");
        List<Map<String, Object>> mapList4 = sqlMapper.selectList("select * from user a,user b where a.id=b.id", myPage);
        log.warn("mapList4=={}", mapList4);
        Page<Map<String, Object>> mapPage2 = sqlMapper.selectPage("select * from user a,user b where a.id=b.id", myPage);
        log.warn("mapPage2=={}", JacksonUtil.toStr(mapPage2));

        User user = sqlMapper.selectOne("select * from user limit 1", User.class);
        log.warn("user=={}", user);                     // user==User(id=1, userName=Jone, age=18, mail=null, addr=null, version=1, deleted=false)

        Map<String, Object> map3 = sqlMapper.selectOne("select id,user_name from user limit 1");
        id = (BigInteger) map3.get("id");
        name = (String) map3.get("user_name");
        log.warn("{}, {}", map3.getClass(), map3);      // class java.util.HashMap, {user_name=Jone, id=1}
        log.warn("{}, {}", id.getClass(), id);          // class java.lang.Long, 1
        log.warn("{}, {}", name.getClass(), name);      // class java.lang.String, Jone

        Map<String, String> map4 = sqlMapper.selectOne("select user_name,email from user limit 1");
        name = map4.get("user_name");
        email = map4.get("email");
        log.warn("{}, {}", map4.getClass(), map4);      // class java.util.HashMap, {user_name=Jone, email=test1@baomidou.com}
        log.warn("{}, {}", name.getClass(), name);      // class java.lang.String, Jone
        log.warn("{}, {}", email.getClass(), email);    // class java.lang.String, test1@baomidou.com


        List<BigInteger> intList = sqlMapper.selectOneColumn("select id from user");
        List<String> strList = sqlMapper.selectOneColumn("select email from user");
        log.warn("{}, {}", intList.get(0).getClass(), intList.get(0));          // class java.lang.Long, 1
        log.warn("{}, {}", strList.get(0).getClass(), strList.get(0));          // class java.lang.String, test1@baomidou.com

        id = sqlMapper.selectOneVal("select id,email from user limit 1");
        log.warn("{}, {}", id.getClass(), id);                          // class java.lang.Long, 1

        name = sqlMapper.selectOneVal("select user_name from user limit 1");
        log.warn("{}, {}", name.getClass(), name);                      // class java.lang.String, Jone

        Long rowCount = sqlMapper.selectOneVal("select count(*) from user");
        log.warn("{}, {}", rowCount.getClass(), rowCount);              // class java.lang.Long, 5

        Integer count = sqlMapper.executeUpdate("update user set user_name = '张三三' where id <=3");
        log.warn("count=={}", count);           // count==3

        count = sqlMapper.executeUpdate("INSERT INTO user (id,user_name) VALUES (55, '五五'), (66, '六六')");
        log.warn("count=={}", count);           // count==2

        count = sqlMapper.executeUpdate("CREATE TABLE test ( user_name varchar(255) NULL)");
        log.warn("count=={}", count);           // count==0

        log.info("万能 sql 执行器 end");
    }


    /** 4、测试自动填充 创建时间、修改时间 */
    @GetMapping("/autoFill")
    private void autoFill() {
        resetDbData();

        userMapper.insert(new User().setUserName("测试自动填充1"));
        userService.save(new User().setUserName("测试自动填充2"));
        userMapper.updateById(new User().setUserName("测试自动填充3").setId(1));
        userService.updateById(new User().setUserName("测试自动填充4").setId(2));
    }

    /** 多租户 */
    @GetMapping("/multiTenant")
    private void multiTenant() {
        resetDbData();

        User user = new User().setUserName("多租户测试");
//        INSERT INTO user (user_name, create_time, update_time, tenant_id) VALUES ('多租户测试', '2022-08-31 19:31:39.541', '2022-08-31 19:31:39.541', 1)
        userMapper.insert(user);
//        SELECT xxx FROM user WHERE id = 6 AND deleted = 0 AND user.tenant_id = 1
        user = userMapper.selectById(user.getId());
        Assertions.assertTrue(1 == user.getTenantId());
    }

    /**
     * 字段脱敏、数据脱敏
     * 脱敏字段，内置 手机号、邮箱、银行卡号 等 9 种常用脱敏规则
     *
     * @param skip 跳过脱敏
     */
    @GetMapping("/fieldSensitive")
    private Object fieldSensitive(@PathVariable(required = false) boolean skip) {
        resetDbData();

        if (skip) {
            RequestDataTransfer.skipSensitive();
        }

        UserSensitive userSensitive = new UserSensitive().setId(1)
            .setChineseName("苞米豆")              // 保留前1个，其他为*
            .setIdCard("130626202209018888")        // 保留后4个，其他为*
            .setPhone("010-12345678")               // 保留后4个，其他为*
            .setMobile("17612345678")               // 保留前3后2个，其他为*
            .setAddress("北京市海淀区1122")           // 保留前3，其他为*
            .setEmail("12345678@qq.com")            // 保留前1或3个，@后面的，其他为*
            .setBankCard("6214111111111234")        // 保留前6后4个，其他为*
            .setPassword("i-love-you")              // 全为*
            .setCarNumber("冀F56789");               // 保留前2后1个，其他为*

        List<UserSensitive> userSensitiveList = ListUtil.list(false, userSensitive, userSensitive.setId(2));
        log.debug("userSensitiveList=={}", userSensitiveList);      // 未脱敏
        return userSensitiveList;                                   // 已脱敏

        /**
         * {
         *   "id": 1,
         *   "chineseName": "苞**",
         *   "idCard": "**************8888",
         *   "phone": "********5678",
         *   "mobile": "176******78",
         *   "address": "北京********",
         *   "email": "123*****@qq.com",
         *   "bankCard": "621411******1234",
         *   "password": "**********",
         *   "carNumber": "冀F****9"
         * }
         */
    }

}